package com.ruoyi.common.core.service;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import com.github.pagehelper.PageHelper;
import com.ruoyi.common.core.domain.BaseEntity;
import com.ruoyi.common.enums.common.State;
import com.ruoyi.common.utils.StringUtils;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.Map;

/**
 * @Classname IService
 * @Author: sunluquan
 * @Date: 2022/1/5 22:03
 * @Description TODO
 * 自定义的顶级 service层
 * 详细请参照{@link com.baomidou.mybatisplus.extension.service.IService}
 */
@Validated
public interface IService<T extends BaseEntity> extends IServiceException{

    /**
     * 默认批次提交数量
     */
    int DEFAULT_BATCH_SIZE = 1000;

    /**
     * 根据 pk 主键编号查询数据
     * @param id 主键编号
     * @param columns
     * @return
     */
    T selectById(@NotNull Serializable id, SFunction<T,?>... columns);

    /**
     * 查询（根据ID 批量查询）
     *
     * @param idList 主键ID列表(不能为 null 以及 empty)
     */
    List<T> selectBatchIds(@NotEmpty Collection<? extends Serializable> idList);

    /**
     * 根据 pk 主键编号查询状态为可用的数据
     * @param id 主键编号
     * @param columns
     * @return
     */
    T selectUsableById(@NotNull Serializable id, SFunction<T,?>... columns);

    /**
     * 查询一条数据记录
     *
     * @param  t 实例对象
     * @param columns 查询指定的列
     * @return 符合条件的实体对象 or null
     */
    default T selectOne(@NotNull T t, SFunction<T,?>... columns){
        return selectOne(t,true,columns);
    }

    /**
     * 查询一条数据记录
     *
     * @param  t
     * @param throwEx 是否抛出异常 如果出现多条数据
     * @param columns 查询指定的列
     * @return 符合条件的实体对象 or null
     */
    default T selectOne(@NotNull T t, boolean throwEx, SFunction<T,?>... columns){
        LambdaQueryWrapper<T> queryWrapper = customLambdaQuery().select(columns);

        queryWrapper.setEntity(t);

        return selectOne(queryWrapper,throwEx);
    }

    /**
     * 根据 Wrapper，查询一条记录 <br/>
     * <p>结果集，如果是多个会抛出异常，随机取一条加上限制条件 wrapper.last("LIMIT 1")</p>
     *
     * @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
     * @return
     */
    default T selectOne(@NotNull Wrapper<T> queryWrapper) {
        return selectOne(queryWrapper, true);
    }

    /**
     * 根据 Wrapper，查询一条记录
     *
     * @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
     * @param throwEx      有多个 result 是否抛出异常
     * @return
     */
    T selectOne(@NotNull Wrapper<T> queryWrapper, boolean throwEx);

    /**
     * 由子类实现  默认抛出不支持的异常
     * 获取所有数据 k表示数据行的唯一标识  v 表示当前对象
     * @return
     */
    default Map<? extends Serializable,T> selectAllMap(){
         throw new UnsupportedOperationException();
    }

    /**
     * 查询列表
     * @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
     * @return
     */
    List<T> selectSimpleList(@NotNull Wrapper<T> queryWrapper) ;

    /**
     * 查询简单的实体列表数据
     * @param t 查询条件
     * @param columns 查询指定列
     * @return 实例列表
     */
    default List<T> selectSimpleList(T t, SFunction<T,?>... columns){
        LambdaQueryWrapper<T> queryWrapper = customLambdaQuery().setEntity(t);
        if(StringUtils.isNotEmpty(columns)){

            queryWrapper.select(columns);

        }
        return selectSimpleList(queryWrapper);
    }

    /**
     * 插入一条记录（选择字段，策略插入）
     *
     * @param entity 实体对象
     * @return
     */
    boolean insert(@NotNull T entity);

    /**
     * 插入（批量）
     *
     * @param entityList 实体对象集合
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    default boolean insertBatch(@NotEmpty Collection<T> entityList) {
        return insertBatch(entityList, DEFAULT_BATCH_SIZE);
    }

    /**
     * 插入（批量）
     * @param entityList 实体对象集合
     * @param batchSize  插入批次数量
     * @return
     */
    boolean insertBatch(@NotEmpty Collection<T> entityList, int batchSize);

    /**
     * 根据 ID 删除
     * @param id 主键ID
     * @return
     */
     boolean deleteById(@NotNull Serializable id) ;

    /**
     * 根据 IDs 删除
     * @param ids 主键IDs
     * @return
     */
    boolean deleteByIds(@NotEmpty Collection<? extends Serializable> ids);

    /**
     * 根据ID 批量更新
     *
     * @param entityList 实体对象集合
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    default boolean updateBatchById(@NotEmpty Collection<T> entityList) {
        return updateBatchById(entityList, DEFAULT_BATCH_SIZE);
    }

    /**
     * 根据ID 批量更新
     *
     * @param entityList 实体对象集合
     * @param batchSize  更新批次数量
     * @return
     */
    boolean updateBatchById(@NotEmpty Collection<T> entityList, int batchSize);

    /**
     * 根据 ID 选择修改
     *
     * @param entity 实体对象
     */
    boolean updateById(@NotNull T entity);

    /**
     * 根据 UpdateWrapper 条件，更新记录 需要设置sqlset
     *
     * @param updateWrapper 实体对象封装操作类 {@link LambdaUpdateWrapper}
     */
    default boolean update(@NotNull LambdaUpdateWrapper<T> updateWrapper) {
        return update(null, updateWrapper);
    }

    /**
     * 根据 whereEntity 条件，更新记录
     *
     * @param entity        实体对象
     * @param updateWrapper 实体对象封装操作类 {@link LambdaUpdateWrapper}
     */
    boolean update(@NotNull T entity, LambdaUpdateWrapper<T> updateWrapper) ;

    /**
     * 查询总记录数
     *
     * @see Wrappers#emptyWrapper()
     */
    default long count() {
        return count(Wrappers.emptyWrapper());
    }

    /**
     * 根据 Wrapper 条件，查询总记录数
     *
     * @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
     */
    default long count(@NotNull Wrapper<T> queryWrapper) {
        return SqlHelper.retCount(getBaseMapper().selectCount(queryWrapper));
    }

    /**
     * 获取对应 entity 的 BaseMapper
     *
     * @return BaseMapper
     */
    BaseMapper<T> getBaseMapper();

    /**
     * 获取 entity 的 class
     *
     * @return {@link Class<T>}
     */
    Class<T> getEntityClass();

    /**
     * entity 是否有state属性
     * @return
     */
    boolean isStateFieldExist();
    /**
     * 查询 lambda 式
     * @return
     */
    default LambdaQueryWrapper<T> lambdaQuery(){
        return Wrappers.lambdaQuery();
    }

    /**
     * 自定义 查询 lambda 式 默认加入状态为可用的
     * @return
     */
    default LambdaQueryWrapper<T> customLambdaQuery(){
        LambdaQueryWrapper<T> lambdaQuery = Wrappers.lambdaQuery();
        buildUsableState(lambdaQuery);
        return lambdaQuery;
    }

    /**
     * 修改 lambda 式
     * @return
     */
    default LambdaUpdateWrapper<T> lambdaUpdate(){
        return Wrappers.lambdaUpdate();
    }

    /**
     * 如果 t 为空 则将条件加入到 queryWrapper 中
     * 如果 t 不为空 并且 state为空 则设置到 t中
     * @param t 条件实体对象
     * @param queryWrapper 查询包装器
     */
    default void buildUsableState(T t,LambdaQueryWrapper<T> queryWrapper){
        if(isStateFieldExist()){
            if(StringUtils.isNull(t)){
                //指定对象类型
                if(StringUtils.isNull(queryWrapper.getEntityClass())){
                    queryWrapper.setEntityClass(getEntityClass());
                }
                queryWrapper.eq(T::getState,State.OK);
            }else if(StringUtils.isNull(t.getState())){
                t.setState(State.OK);
            }
        }
    }

    /**
     * 构建可用的查询参数
     * @param t
     */
    default void buildUsableState(@NotNull T t){
        buildUsableState(t,null);
    }
    /**
     * 将条件加入到 queryWrapper 中
     * @param queryWrapper
     */
    default void buildUsableState(LambdaQueryWrapper<T> queryWrapper){

        buildUsableState(null,queryWrapper);
    }
    /**
     * 获取有排序字段的表的最大排序值
     * @param entity 最大值的分组条件 如果没有则是所有数据的最大排序值
     * @return
     */
    default Integer getMaxOfWeight(T entity){
        //只需要返回一条数据
        PageHelper.startPage(0,1,false);

        LambdaQueryWrapper<T> queryWrapper = lambdaQuery();
        if(StringUtils.isNotNull(entity)){
            queryWrapper.setEntity(entity);
        }

        queryWrapper.orderByDesc(BaseEntity::getWeight);
        queryWrapper.select(BaseEntity::getWeight);
        T t = selectOne(queryWrapper);
        Integer weight = t==null?0:t.getWeight();

        return weight;
    }
    /**
     * 获取有排序字段的表的最大排序值
     * @return 返回数据行中的最大排序值
     */
    default Integer getMaxOfWeight(){
        return getMaxOfWeight(null);
    }
}
